<script setup lang="ts">
import { ref, computed, reactive } from 'vue'

interface Props {
  data: any
  colorScheme: Record<string, string>
  maxDepth?: number
}

const props = withDefaults(defineProps<Props>(), {
  maxDepth: 10
})

interface TreeNode {
  key?: string
  value: any
  type: 'object' | 'array' | 'string' | 'number' | 'boolean' | 'null'
  level: number
  path: string
  collapsed: boolean
  hasChildren: boolean
  childCount?: number
}

const collapsedNodes = reactive(new Set<string>())

// 获取值的类型
function getValueType(value: any): TreeNode['type'] {
  if (value === null) return 'null'
  if (Array.isArray(value)) return 'array'
  if (typeof value === 'object') return 'object'
  return typeof value as TreeNode['type']
}

// 获取子元素数量
function getChildCount(value: any): number {
  if (Array.isArray(value)) return value.length
  if (typeof value === 'object' && value !== null) return Object.keys(value).length
  return 0
}

// 切换节点折叠状态
function toggleCollapse(path: string) {
  if (collapsedNodes.has(path)) {
    collapsedNodes.delete(path)
  } else {
    collapsedNodes.add(path)
  }
}

// 构建树节点结构
const treeNodes = computed(() => {
  const nodes: TreeNode[] = []
  
  function traverse(value: any, key?: string, level = 0, path = ''): TreeNode[] {
    if (level > props.maxDepth) return []
    
    const nodeType = getValueType(value)
    const hasChildren = nodeType === 'object' || nodeType === 'array'
    const isCollapsed = collapsedNodes.has(path)
    
    const node: TreeNode = {
      key,
      value,
      type: nodeType,
      level,
      path,
      collapsed: isCollapsed,
      hasChildren,
      childCount: hasChildren ? getChildCount(value) : 0
    }
    
    const result = [node]
    
    // 如果节点未折叠且有子节点，递归处理子节点
    if (hasChildren && !isCollapsed) {
      if (nodeType === 'array') {
        value.forEach((item: any, i: number) => {
          result.push(...traverse(item, `[${i}]`, level + 1, `${path}[${i}]`))
        })
      } else if (nodeType === 'object') {
        Object.entries(value).forEach(([k, v]) => {
          result.push(...traverse(v, k, level + 1, `${path}.${k}`))
        })
      }
    }
    
    return result
  }
  
  return traverse(props.data)
})

// 渲染单个值（带语法高亮）
function renderValue(node: TreeNode): string {
  const { value, type } = node
  const colors = props.colorScheme
  
  switch (type) {
    case 'null':
      return `<span style="color: ${colors.null}">null</span>`
    case 'string':
      return `<span style="color: ${colors.string}">"${value}"</span>`
    case 'number':
      return `<span style="color: ${colors.number}">${value}</span>`
    case 'boolean':
      return `<span style="color: ${colors.boolean}">${value}</span>`
    case 'array':
      return `<span style="color: ${colors.bracket}">[</span><span style="color: ${colors.punctuation}"> ${node.childCount} items </span><span style="color: ${colors.bracket}">]</span>`
    case 'object':
      return `<span style="color: ${colors.bracket}">{</span><span style="color: ${colors.punctuation}"> ${node.childCount} keys </span><span style="color: ${colors.bracket}">}</span>`
    default:
      return String(value)
  }
}

// 获取缩进样式
function getIndentStyle(level: number) {
  return {
    paddingLeft: `${level * 20}px`
  }
}

// 判断是否显示逗号
function shouldShowComma(node: TreeNode, index: number, nodes: TreeNode[]): boolean {
  if (index === nodes.length - 1) return false
  
  const currentLevel = node.level
  const nextNode = nodes[index + 1]
  
  // 如果下一个节点的层级小于等于当前层级，说明当前节点是最后一个同级元素
  if (nextNode && nextNode.level <= currentLevel) {
    return false
  }
  
  return true
}

// 获取展开/折叠图标
function getToggleIcon(node: TreeNode): string {
  if (!node.hasChildren) return ''
  return node.collapsed ? '▶' : '▼'
}
</script>

<template>
  <div class="json-highlight-tree font-mono text-sm">
    <div 
      v-for="(node, index) in treeNodes" 
      :key="node.path"
      class="json-line flex items-center hover:bg-gray-50 dark:hover:bg-gray-800 py-1 px-2 rounded transition-colors"
      :style="getIndentStyle(node.level)"
    >
      <!-- 展开/折叠按钮 -->
      <button
        v-if="node.hasChildren"
        @click="toggleCollapse(node.path)"
        class="toggle-btn w-4 h-4 flex items-center justify-center text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 mr-1 transition-colors"
        :class="{ 'rotate-90': !node.collapsed }"
      >
        {{ getToggleIcon(node) }}
      </button>
      <span v-else class="w-5"></span>
      
      <!-- 键名 -->
      <span 
        v-if="node.key !== undefined" 
        class="json-key mr-1"
        :style="{ color: colorScheme.key }"
      >
        "{{ node.key }}"
      </span>
      
      <!-- 冒号 -->
      <span 
        v-if="node.key !== undefined" 
        class="json-colon mr-1"
        :style="{ color: colorScheme.punctuation }"
      >
        :
      </span>
      
      <!-- 值 -->
      <span 
        class="json-value"
        v-html="renderValue(node)"
      ></span>
      
      <!-- 逗号 -->
      <span 
        v-if="shouldShowComma(node, index, treeNodes)"
        class="json-comma"
        :style="{ color: colorScheme.punctuation }"
      >
        ,
      </span>
      
      <!-- 折叠时显示的省略号 -->
      <span 
        v-if="node.hasChildren && node.collapsed && node.childCount > 0"
        class="json-ellipsis ml-2 text-gray-400"
      >
        ...
      </span>
    </div>
  </div>
</template>

<style scoped>
.json-highlight-tree {
  line-height: 1.5;
}

.json-line {
  min-height: 24px;
  cursor: default;
}

.toggle-btn {
  cursor: pointer;
  border: none;
  background: none;
  font-size: 10px;
  transition: transform 0.2s ease;
}

.toggle-btn:hover {
  transform: scale(1.2);
}

.json-key {
  font-weight: 500;
}

.json-value {
  flex: 1;
}

.json-ellipsis {
  font-style: italic;
  font-size: 12px;
}

/* 选中文本样式 */
.json-line::selection,
.json-line *::selection {
  background-color: rgba(59, 130, 246, 0.3);
}

/* 深色模式下的选中样式 */
.dark .json-line::selection,
.dark .json-line *::selection {
  background-color: rgba(59, 130, 246, 0.5);
}
</style>